/**********************************************************************
 * 
 * Name: UpsertExWarehouseREST
 * Object: ExWarehouse__c, ExWarehouse_Detail__c
 * Purpose: Upsert ExWarehouse and ExWarehouse detail list from NC
 * Requirement:
 * Author: kittylau (382376269@qq.com)
 * Create Date: 2017-01-15
 * Modify History: 
 * 
 * @Url: /services/apexrest/CRM/upsertExWarehouseREST
 * 接收的Json数据格式:
   {
    "data":[
        {
            //主表数据
            "dbillcode":"出库单号",
            "cgeneralhid":"出库单据表头PK",
            "ckname":"仓库",
            "dbilldate":"出库日期",
            "currtypename":"币种",
            "corpcode":"公司编码",
            "corpname":"公司名称",
            "custcode":"客户编码",
            "custname":"客户名称",
            //从表数据
            "cgeneralbid":"出库单据表体PK",
            "salecode":"销售订单号",
            "sale_hid":"销售订单主表ID",
            "sale_bid":"销售订单从表ID",
            "invcode":"存货编码",
            "invname":"存货名称",
            "invdm":"存货代码",
            "vbatchcode":"批次号",
            "nshouldoutnum":"应发数量",
            "nnum":"实发数量",
            "dproducedate":"生产日期",
            "dvalidate":"失效日期",
            "ts":"最后更新时间",
            
            //v1.4新增主表
            "rowno":"行号",
            "zdkh":"终端客户",
            "memo":"备注",
            "bodyname":"库存组织",
            "ck":"仓库",
            "cbiztype":"业务流程",
            "ywyname":"业务员",
            "deptname":"部门",
            "xsqy":"销售区域",
            "ntaxrate":"税率",
            "kpfs":"开票方式",
            "sflx":"收发类别",
            "iszx":"是否直销",
            "isfq":"是否分期销售",
            //v1.4新增从表
            "sa03":"客户发货要求",
            "so01":"销售订单表头产品线",
            "mk01":"联系电话",
            "mk2":"收货信息",
            "noriginalcursummny":"税价合计",
            "invtype":"型号",
            "invspec":"规格",
            "jldw":"单位",
            "nquotemny":"实际金额",
            "vreceiveaddress":"表体收货地址",
            "addrname":"表体联系人",
            "addrphone":"表体联系电话",
            "dbizdate":"出库日期",
            "vbodynote":"表体备注",
            "csourcetype":"来源单据类型编码",
            "cfirsttype":"源头单据类型编码",
            "invpinpai":"品牌",
            "cinvbasid":"存货基本档案pk",
            "def8":"客户自定义项8",
            "invshortname":"存货简称",
            "daccountdate":"库房签字日期"
        },
        {...}
        ]
   }
*  返回的Json数据格式：
  {
    "result":"0 OR 1 , 1表示成功，0表示失败", 
    "result_msg":"成功为空，失败时为失败原因信息",
    "ts":"所有记录中,更新时间最近的那一条记录的更新时间"
  }
*************************************************************************/
@RestResource(urlMapping='/CRM/upsertExWarehouseREST/*')
global without sharing class UpsertExWarehouseREST {
    @HttpPost
    global static RestReturnMessage upsertExWarehouse(List<ExWarehouseRestArgs> data) {
        RestReturnMessage msg = null;
        try{
            if(data.size() > 0){
                msg = doUpsertExWarehouse(data);
            }else{
                throw new DmlException('没有数据');
            }
        }
        catch(Exception e){
            System.debug(LoggingLevel.INFO, '*** 错误信息: ' + e.getMessage() );
            System.debug(LoggingLevel.INFO, '*** 错误跟踪: ' + e.getStackTraceString());
            msg = Utils.getRestReturnMessage(false, e.getMessage() + ' - ' + e.getStackTraceString(),new List<Map<String ,String>>());
        }
        return msg;
    }

    //得到POST数据，完成ExWarehouse数据的插入或更新
    global static RestReturnMessage doUpsertExWarehouse (List<ExWarehouseRestArgs> data) {
       RestReturnMessage message = null;
        Datetime maxTs = Datetime.valueOf(Utils.MIN_DATE_TIME);
        System.debug(LoggingLevel.INFO, '*** ExWarehouse Data FROM NC: ' + data);

        //保存传过来的出库单号 : 2017.7.5 : 修改为PK
        Map<String,String> mapCodes = new Map<String,String>();
        //保存传过来的客户编号
        Map<String,String> mapAccount = new Map<String,String>();
        //保存传过来的产品编号
        Map<String,String> mapProduct = new Map<String,String>();
        for(ExWarehouseRestArgs exw : data){
            //因为销售发票是主从表结构，但是NC传过来的数据是扁平化后报表样式的(主表和从表JOIN后的数据)
            /*if(!mapCodes.containsKey(exw.dbillcode)){
                mapCodes.put(exw.dbillcode,exw.dbillcode);
            }*/
            if(!mapCodes.containsKey(exw.cgeneralhid)){
                mapCodes.put(exw.cgeneralhid,exw.cgeneralhid);
            }
            if(!mapAccount.containsKey(exw.custcode)){
                mapAccount.put(exw.custcode, exw.custcode);
            }
            ///添加 接口调用客户  用来匹配没有找到客户的出库单
            mapAccount.put('JKDYKH','JKDYKH');
            if(!mapProduct.containsKey(exw.cinvbasid)){
                mapProduct.put(exw.cinvbasid, exw.cinvbasid);
            }
            //如果当前记录的更新时间大于最大时间(maxTs)，则设置最大时间为当前记录时间
            Datetime dt = Utils.parseDatetime(exw.ts);
            if(dt > maxTs){
                maxTs = dt;
            }
        }
        //得到产品记录
        List<Product__c> productList = [SELECT Id,Name,NCCode__c,pk_invbasdoc__c FROM Product__c WHERE pk_invbasdoc__c IN :mapProduct.keySet()];
        mapProduct.clear();
        for(Product__c p : productList){
            mapProduct.put(p.pk_invbasdoc__c, p.Id);
        }
        //得到已存在的出库单主表记录
        List<ExWarehouse__c> exwList = 
                    [SELECT Id,Name,Account__c,memo__c,currtypename__c,deptname__c,ckname__c,ck__c,
                        cgeneralhid__c,dbilldate__c,corpcode__c,corpname__c,kpfs__c,custcode__c,
                        sa03__c,custname__c,bodyname__c,isfq__c,iszx__c,sflx__c,ntaxrate__c,xsqy__c,
                        cbiztype__c,ywyname__c,zdkh__c   
                    FROM ExWarehouse__c 
                    WHERE cgeneralhid__c IN :mapCodes.keySet()];
        //把已存在的ExWarehouse保存在Map中以用来区别是新增或更新
        Map<String,ExWarehouse__c> mapExistExWarehouse = new Map<String,ExWarehouse__c>();
        for(ExWarehouse__c exw : exwList){
            mapExistExWarehouse.put(exw.cgeneralhid__c, exw);
        }

        //得到已存在的出库单明细数据
        List<ExWarehouse_Detail__c> exwItemList = 
                    [SELECT Id,Name,ExWarehouse__c,Product__c,vbodynote__c,addrphone__c,
                        addrname__c,vreceiveaddress__c,outcode__c,dbizdate__c,invcode__c,
                        invdm__c,invname__c,jldw__c,invspec__c,csourcetype__c,mk01__c,
                        vbatchcode__c,dproducedate__c,dvalidate__c,nnum__c,nquotemny__c,
                        mk2__c,noriginalcursummny__c,so01__c,sale_bid__c,salecode__c,
                        sale_hid__c,invtype__c,nshouldoutnum__c,cfirsttype__c,exwarehaouse_hid__c
                    FROM ExWarehouse_Detail__c 
                    WHERE exwarehaouse_hid__c IN :mapCodes.keySet()];
        Map<String,ExWarehouse_Detail__c> mapExistExWarehouseItem = new Map<String,ExWarehouse_Detail__c>();
        for(ExWarehouse_Detail__c item : exwItemList){
            // mapExistExWarehouseItem.put(item.outcode__c + '-' + item.salecode__c + '-' + item.sale_bid__c, item);
            mapExistExWarehouseItem.put(genKey4ExWarehouseDetail(item.outcode__c, item.exwarehaouse_hid__c, item.Name), item);
        }
        System.debug(LoggingLevel.INFO, '*** Exist ExWarehouse On CRM: ' + exwList);
        System.debug(LoggingLevel.INFO, '*** Exist ExWarehouse Detail On CRM: ' + exwItemList);

        //得到NC客户编号和CRM客户Id对应关系
        List<Account> accList = new List<Account>([SELECT Id,Name,AccountNumber FROM Account WHERE AccountNumber IN :mapAccount.keySet()]);
        mapAccount.clear();
        for(Account acc : accList){
            if(!mapAccount.containsKey(acc.AccountNumber)){
                mapAccount.put(acc.AccountNumber, acc.Id);
            }
        }
        //用来保存从表pk的记录集合
        List<Map<String,String>> pkList = new List<Map<String,String>>();
        //用来保存或更新的出库单主表的记录集合
        List<ExWarehouse__c> saveList = new List<ExWarehouse__c>();
        //用来保存或更新的出库单从表记录集合
        List<ExWarehouse_Detail__c> saveItemList = new List<ExWarehouse_Detail__c>();
        //用来记录主表记录是否已在下面的for循环中已操作
        Map<String,String> hasRunCodes = new Map<String,String>();
        //新建或更新现存ExWarehouse__c/ExWarehouse_Detail__c记录
        for(ExWarehouseRestArgs exw : data){
            if(exw.cgeneralhid != null){
                //如果主表记录已处理过了，则不再处理主表数据，只处理从表数据
                if(!hasRunCodes.containsKey(exw.cgeneralhid)){
                    //记录本条记录的主表数据已处理过了
                    hasRunCodes.put(exw.cgeneralhid, '');
                    //主表数据
                    ExWarehouse__c exwForSave = null;
                    if(mapExistExWarehouse.containsKey(exw.cgeneralhid)){
                        exwForSave = mapExistExWarehouse.get(exw.cgeneralhid);
                    }else{
                        exwForSave = new ExWarehouse__c();
                    }
                    exwForSave.Name = exw.dbillcode;//出库单号
                    exwForSave.cgeneralhid__c = exw.cgeneralhid;//出库单主表ID
                    exwForSave.currtypename__c = exw.currtypename;//币种
                    exwForSave.ckname__c = exw.ckname;//仓库
                    exwForSave.corpcode__c = exw.corpcode;//公司编码
                    exwForSave.corpname__c = exw.corpname;//公司名称
                    exwForSave.custcode__c = exw.custcode;//客户编码
                    exwForSave.custname__c = exw.custname;//客户名称
                    exwForSave.memo__c = exw.memo;//备注
                    exwForSave.deptname__c = exw.deptname;//部门
                    exwForSave.ck__c = exw.ck;//仓库
                    exwForSave.kpfs__c = exw.kpfs;//开票方式
                    exwForSave.sa03__c = exw.sa03;//客户发货要求
                    exwForSave.bodyname__c = exw.bodyname;//库存组织
                    exwForSave.isfq__c = exw.isfq == 'Y'?'是':'否';//是否分期销售(Y/N)
                    exwForSave.iszx__c = exw.iszx=='Y'?'是':'否';//是否直销(Y/N)
                    exwForSave.sflx__c = exw.sflx;//收发类别
                    exwForSave.xsqy__c = exw.xsqy;//销售区域
                    exwForSave.cbiztype__c = exw.cbiztype;//业务流程
                    exwForSave.ywyname__c = exw.ywyname;//业务员
                    exwForSave.zdkh__c  = exw.zdkh;//终端客户
             
                    ///如果没有找到客户 ,匹配为预设的客户 
                    exwForSave.Account__c = mapAccount.containsKey(exw.custcode)?mapAccount.get(exw.custcode):mapAccount.get('JKDYKH');//客户  
                    try{
                        exwForSave.dbilldate__c = Date.valueOf(exw.dbilldate);//出库日期
                    }catch(Exception e){
                        exwForSave.dbilldate__c = null;
                    }
                    try{
                        exwForSave.ntaxrate__c = Decimal.valueOf(exw.ntaxrate)/100;//税率
                    }catch(Exception e){
                        exwForSave.ntaxrate__c = null;
                    }
                    saveList.add(exwForSave);
                }
                //从表数据
                ExWarehouse_Detail__c exwItem = null;
                // String key = exw.dbillcode + '-' + exw.cgeneralhid + '-' + exw.cgeneralbid;
                String key = genKey4ExWarehouseDetail(exw.dbillcode,exw.cgeneralhid,exw.cgeneralbid);
                if(mapExistExWarehouseItem.containsKey(key)){
                    exwItem = mapExistExWarehouseItem.get(key);
                }else{
                    exwItem = new ExWarehouse_Detail__c();
                }
                exwItem.Name = exw.cgeneralbid;//出库单明细ID
                exwItem.exwarehaouse_hid__c = exw.cgeneralhid;//出库单主表ID
                exwItem.outcode__c = exw.dbillcode;//出库单号
                exwItem.salecode__c = exw.salecode;//销售订单号
                exwItem.sale_hid__c = exw.sale_hid;//销售订单主表ID
                exwItem.sale_bid__c = exw.sale_bid;//销售订单从表ID
                exwItem.invcode__c = exw.invcode;//存货编码
                exwItem.invname__c = exw.invname;//存货名称
                exwItem.invdm__c = exw.invdm;//存货代码
                exwItem.Product__c = mapProduct.containsKey(exw.cinvbasid)?mapProduct.get(exw.cinvbasid):null;//产品
                exwItem.vbatchcode__c = exw.vbatchcode;//批次号
                exwItem.so01__c = exw.so01;//销售订单表头产品线
                exwItem.mk01__c = exw.mk01;//联系电话
                exwItem.mk2__c = exw.mk2;//收货信息
                exwItem.invtype__c = exw.invtype;//型号
                exwItem.invspec__c = exw.invspec;//规格
                exwItem.jldw__c = exw.jldw;//单位
                exwItem.vreceiveaddress__c = exw.vreceiveaddress;//表体收货地址
                exwItem.addrname__c = exw.addrname;//表体联系人
                exwItem.addrphone__c = exw.addrphone;//表体联系电话
                exwItem.vbodynote__c = exw.vbodynote;//表体备注
                exwItem.csourcetype__c = exw.csourcetype;//来源单据类型编码
                exwItem.cfirsttype__c = exw.cfirsttype;//源头单据类型编码
                exwItem.invpinpai__c = exw.invpinpai;//品牌
                exwItem.cinvbasid__c = exw.cinvbasid;//存货基本档案pk
                exwItem.def8__c = exw.def8;//客户自定义项8
                exwItem.invshortname__c = exw.invshortname;//存货简称
                exwItem.dr__c = exw.dr=='1'?true:false;//删除标记
                try{
                    exwItem.dbizdate__c = Date.valueOf(exw.dbizdate);//出库日期
                }catch(Exception e){
                    exwItem.dbizdate__c = null;
                }
                try{
                    exwItem.noriginalcursummny__c = Decimal.valueOf(exw.noriginalcursummny);//税价合计
                }catch(Exception e){
                    exwItem.noriginalcursummny__c = 0;
                }
                try{
                    exwItem.nquotemny__c = Decimal.valueOf(exw.nquotemny);//实际金额
                }catch(Exception e){
                    exwItem.nquotemny__c = 0;
                }
                try{
                    exwItem.nshouldoutnum__c = Decimal.valueOf(exw.nshouldoutnum);//应发数量
                }catch(Exception e){
                    exwItem.nshouldoutnum__c = 0;
                }
                try{
                    exwItem.nnum__c = Decimal.valueOf(exw.nnum);//实发数量
                }catch(Exception e){
                    exwItem.nnum__c = 0;
                }
                try{
                    exwItem.dproducedate__c = Date.valueOf(exw.dproducedate);//生产日期
                }catch(Exception e){
                    exwItem.dproducedate__c = null;
                }
                try{
                    exwItem.dvalidate__c = Date.valueOf(exw.dvalidate);//失效日期
                    if(exwItem.dvalidate__c.year() > 3000)exwItem.dvalidate__c = Date.newInstance(2999, 12, 31);
                }catch(Exception e){
                    exwItem.dvalidate__c = null;
                }
                saveItemList.add(exwItem);
                ///拼接 返回的pk
                Map<String,String>pk = new Map<String ,String>();
                pk.put('mainpk',exw.cgeneralhid);
                pk.put('sonpk',exw.cgeneralbid);
                pkList.add(pk);

               /* if(!mapExistExWarehouseItem.containsKey(key)){
                    saveItemList.add(exwItem);
                }*/
            }
        }

        ///设置事务还原点，当操作失败时用来回滚
        SavePoint sp = Database.setSavePoint();
        try{
            //保存主表数据
            Upsert saveList cgeneralhid__c;
            //取得保存后的出库单Id和NC出库单号的对应关系
            mapCodes.clear();
            for(ExWarehouse__c exw : saveList){
                if(!mapCodes.containsKey(exw.cgeneralhid__c)){
                    mapCodes.put(exw.cgeneralhid__c, exw.Id);
                }
            }
            //设置从表的ExWarehouse_Id
            for(ExWarehouse_Detail__c dexw : saveItemList){
                dexw.ExWarehouse__c = mapCodes.containsKey(dexw.exwarehaouse_hid__c)?mapCodes.get(dexw.exwarehaouse_hid__c):null;
            }
            //保存从表数据
            Upsert saveItemList name;
			
            message = Utils.getRestReturnMessage(true,'',pkList);

            //message = Utils.getRestReturnMessage(true,'成功导入[' + saveList.size()+ '/' + data.size() + ']条记录',maxTs);
        }
        catch(Exception e) {
            System.debug(LoggingLevel.INFO, '*** 错误信息: ' + e.getMessage() );
            System.debug(LoggingLevel.INFO, '*** 错误跟踪: ' + e.getStackTraceString());
            //保存数据失败，回滚事务
            Database.rollback(sp);
            message =  Utils.getRestReturnMessage(false, e.getMessage() + ' - ' + e.getStackTraceString(),pkList);
        }
        
        return message; 
    }

    private static String genKey4ExWarehouseDetail(String id1, String id2, String id3){
        return id1 + '-' + id2 + '-' + id3;
    }

    //根据NC提供的JSON结构来确定的ExWarehouse字段集合
    global class ExWarehouseRestArgs {
        //主表数据
        global String dbillcode;//出库单号
        global String cgeneralhid;//出库单据表头PK
        global String ckname;//仓库
        global String dbilldate;//出库日期
        global String currtypename;//币种
        global String corpcode;//公司编码
        global String corpname;//公司名称
        global String custcode;//客户编码
        global String custname;//客户名称
        //从表数据
        global String cgeneralbid;//出库单据表体PK
        global String salecode;//销售订单号
        global String sale_hid;//销售订单主表ID
        global String sale_bid;//销售订单从表ID
        global String invcode;//存货编码
        global String invname;//存货名称
        global String invdm;//存货代码
        global String vbatchcode;//批次号
        global String nshouldoutnum;//应发数量
        global String nnum;//实发数量
        global String dproducedate;//生产日期
        global String dvalidate;//失效日期
        global String ts;//最后更新时间
        //v1.4新增主表
        global String rowno;//行号
        global String zdkh;//终端客户
        global String memo;//备注
        global String sa03;//客户发货要求
        global String kpfs;//开票方式
        global String sflx;//收发类别
        global String bodyname;//库存组织
        global String ck;//仓库
        global String cbiztype;//业务流程
        global String ywyname;//业务员
        global String deptname;//部门
        global String xsqy;//销售区域
        global String ntaxrate;//税率
        global String iszx;//是否直销(Y/N)
        global String isfq;//是否分期销售(Y/N)
        //v1.4新增从表
        global String so01;//销售订单表头产品线
        global String mk01;//联系电话
        global String mk2;//收货信息
        global String noriginalcursummny;//税价合计
        global String invtype;//型号
        global String invspec;//规格
        global String jldw;//单位
        global String nquotemny;//实际金额
        global String vreceiveaddress;//表体收货地址
        global String addrname;//表体联系人
        global String addrphone;//表体联系电话
        global String dbizdate;//出库日期
        global String vbodynote;//表体备注
        global String csourcetype;//来源单据类型编码
        global String cfirsttype;//源头单据类型编码
        global String invpinpai;//品牌
        global String cinvbasid;//存货基本档案pk
        global String def8;//客户自定义项8
        global String invshortname;//存货简称
        //v1.5新增从表 nc那边传过来的数据里面多了一个dr字段，1或者0
        global String dr;
        // 0418 新增字段，不用保存SF，只是为了接受数据时不报错
        global String vstorecondition;
        global String vdotechnics;
        global String vapprovalnum;
        global String daccountdate;//库房签字日期
    }
}